/*
 *      Copyright 2008, M.B.I. srl.
 * 
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 3 of the License, or
 *      (at your option) any later version.
 *      
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *      
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */

#include <boost/python.hpp>
#include <stdexcept>
#include <sstream>
#include <new>
 
#include "OsiSolverInterface.hpp"
#include "CoinWarmStart.hpp"
#include "CoinPackedMatrix.hpp"

#include "pyOsiCommon.hpp"

// OSIWrap 
/*
 * Struct to wrap OsiSolverInterface, defining a default implementation
 * for pure virtual methods
 */
struct OSIWrap : OsiSolverInterface, boost::python::wrapper<OsiSolverInterface>{   
    void initialSolve() { this->get_override("initialSolve"); }
    void resolve() { this->get_override("resolve"); }
    void branchAndBound() { this->get_override("branchAndBound"); }
    bool isAbandoned() const { this->get_override("isAbandoned"); return true;}
    bool isProvenOptimal() const { this->get_override("isProvenOptimal"); return true;}
    bool isProvenPrimalInfeasible() const { this->get_override("isProvenPrimalInfeasible"); return true;}
    bool isProvenDualInfeasible() const { this->get_override("isProvenDualInfeasible"); return true;}
    bool isPrimalObjectiveLimitReached() const { this->get_override("isPrimalObjectiveLimitReached"); return true;}
    bool isDualObjectiveLimitReached() const { this->get_override("isDualObjectiveLimitReached"); return true;}
    bool isIterationLimitReached() const { this->get_override("isIterationLimitReached"); return true;} 
    CoinWarmStart* getEmptyWarmStart() const { this->get_override("getEmptyWarmStart"); return 0;}   
    CoinWarmStart* getWarmStart() const { this->get_override("getWarmStart"); return 0;} 
    bool setWarmStart(const CoinWarmStart*) { this->get_override("setWarmStart"); return true;} 
    int getNumCols() const { this->get_override("getNumCols"); return 0;}    
    int getNumRows() const { this->get_override("getNumRows"); return 0;}    
    int getNumElements() const { this->get_override("getNumElements"); return 0;}    
    const double* getColLower() const { this->get_override("getColLower"); return 0;}    
    const double* getColUpper() const { this->get_override("getColUpper"); return 0;}    
    const char* getRowSense() const { this->get_override("getRowSense"); return 0;}  
    const double* getRightHandSide() const { this->get_override("getRightHandSide"); return 0;}  
    const double* getRowRange() const { this->get_override("getRowRange"); return 0;}    
    const double* getRowLower() const { this->get_override("getRowLower"); return 0;}    
    const double* getRowUpper() const { this->get_override("getRowUpper"); return 0;}    
    const double* getObjCoefficients() const { this->get_override("getObjCoefficients"); return 0;}  
    double getObjSense() const { this->get_override("getObjSense"); return 0;}   
    bool isContinuous(int) const { this->get_override("isContinuous"); return true;}    
    const CoinPackedMatrix* getMatrixByRow() const { this->get_override("getMatrixByRow"); return 0;}    
    const CoinPackedMatrix* getMatrixByCol() const { this->get_override("getMatrixByCol"); return 0;}    
    double getInfinity() const { this->get_override("getInfinity"); return 0;}   
    const double* getColSolution() const { this->get_override("getColSolution"); return 0;}  
    const double* getRowPrice() const { this->get_override("getRowPrice"); return 0;}    
    const double* getReducedCost() const { this->get_override("getReducedCost"); return 0;}  
    const double* getRowActivity() const { this->get_override("getRowActivity"); return 0;}  
    double getObjValue() const { this->get_override("getObjValue"); return 0;}   
    int getIterationCount() const { this->get_override("getIterationCount"); return 0;}  
    std::vector<double*, std::allocator<double*> > getDualRays(int) const { this->get_override("getDualRays"); return std::vector<double*>();}    
    std::vector<double*, std::allocator<double*> > getPrimalRays(int) const { this->get_override("getPrimalRays"); return std::vector<double*>();}    
    void setObjCoeff(int, double) { this->get_override("setObjCoeff"); }    
    void setObjSense(double) { this->get_override("setObjSense"); } 
    void setColLower(int, double) { this->get_override("setColLower"); }    
    void setColUpper(int, double) { this->get_override("setColUpper"); }    
    void setRowLower(int, double) { this->get_override("setRowLower"); }    
    void setRowUpper(int, double) { this->get_override("setRowUpper"); }    
    void setRowType(int, char, double, double) { this->get_override("setRowType"); }    
    void setColSolution(const double*) { this->get_override("setColSolution"); }    
    void setRowPrice(const double*) { this->get_override("setRowPrice"); }  
    void setContinuous(int) { this->get_override("setContinuous"); }    
    void setInteger(int) { this->get_override("setInteger"); }  
    void addCol(const CoinPackedVectorBase&, const double, const double, const double) { this->get_override("addCol"); }  
    void deleteCols(const int, const int*) { this->get_override("deleteCols"); }  
    void addRow(const CoinPackedVectorBase&, const double, const double) { this->get_override("addRow"); }  
    void addRow(const CoinPackedVectorBase&, const char, const double, const double) { this->get_override("addRow"); }    
    void deleteRows(const int, const int*) { this->get_override("deleteRows"); }  
    void loadProblem(const CoinPackedMatrix&, const double*, const double*, const double*, const double*, const double*) { this->get_override("loadProblem"); } 
    void assignProblem(CoinPackedMatrix*&, double*&, double*&, double*&, double*&, double*&) { this->get_override("assignProblem"); }   
    void loadProblem(const CoinPackedMatrix&, const double*, const double*, const double*, const char*, const double*, const double*) { this->get_override("loadProblem"); }    
    void assignProblem(CoinPackedMatrix*&, double*&, double*&, double*&, char*&, double*&, double*&) { this->get_override("assignProblem"); }   
    void loadProblem(const int, const int, const CoinBigIndex*, const int*, const double*, const double*, const double*, const double*, const double*, const double*) { this->get_override("loadProblem"); }    
    void loadProblem(const int, const int, const CoinBigIndex*, const int*, const double*, const double*, const double*, const double*, const char*, const double*, const double*) { this->get_override("loadProblem"); }   
    void writeMps(const char*, const char*, double) const { this->get_override("writeMps"); }   
    OsiSolverInterface* clone(bool) const { this->get_override("clone"); return 0;}  
    void applyRowCut(const OsiRowCut&) { this->get_override("applyRowCut"); }   
    void applyColCut(const OsiColCut&) { this->get_override("applyColCut"); }
};

struct WarmStartWrap : CoinWarmStart, boost::python::wrapper<CoinWarmStart>{
    CoinWarmStart* clone() const { this->get_override("clone"); return 0;}
};

template<>
class const_ptr_Wrap<CoinPackedMatrix>{
    public:    
    const_ptr_Wrap() : thePtr(0){
        #ifndef NDEBUG
        LOG_CALL
        #endif
    }
    
    const_ptr_Wrap( const CoinPackedMatrix * aPtr ) :  thePtr(aPtr){
        #ifndef NDEBUG
        LOG_CALL
        LOG_STREAM << thePtr << std::endl;
        #endif
    }
    
    arraySize length() const {
        #ifndef NDEBUG
        LOG_CALL
        #endif
        return thePtr->getSizeVectorStarts()-1;
    }
    
    boost::python::tuple getItem(arraySize aIndex) const {
        #ifndef NDEBUG
        LOG_CALL
        if ( int(aIndex) >= thePtr->getSizeVectorStarts()-1 )
            throw std::out_of_range("Index out of range");
        #endif
        const CoinBigIndex myStart = thePtr->getVectorStarts()[aIndex];
        const int myLen = thePtr->getVectorSize(aIndex);
        
        return boost::python::make_tuple(cptr_double(thePtr->getElements()+myStart,myLen),
                                         cptr_int(thePtr->getIndices()+myStart,myLen));
    }
    
    boost::python::str repr() const {
        int nelem = thePtr->getNumElements();
        const double * values = thePtr->getElements();
        return cptr_double(values, nelem).repr();
    }
    
    private:
    const CoinPackedMatrix * thePtr;
};

// Function(pointer) definition 
/* 
 * Explicitate overloading and modify some critical signature 
 */
void    (OsiSolverInterface::*setColLower_0)(int, double) = &OsiSolverInterface::setColLower;
void    (OsiSolverInterface::*setColLower_1)(const double *) = &OsiSolverInterface::setColLower;
void    (OsiSolverInterface::*setColUpper_0)(int, double) = &OsiSolverInterface::setColUpper;
void    (OsiSolverInterface::*setColUpper_1)(const double *) = &OsiSolverInterface::setColUpper;
void    (OsiSolverInterface::*setContinuous_0)(int) = &OsiSolverInterface::setContinuous;
void    (OsiSolverInterface::*setContinuous_1)(const int *, int) = &OsiSolverInterface::setContinuous;
void    (OsiSolverInterface::*setInteger_0)(int) = &OsiSolverInterface::setInteger;
void    (OsiSolverInterface::*setInteger_1)(const int *, int) = &OsiSolverInterface::setInteger;
void    (OsiSolverInterface::*addCol_0)(const CoinPackedVectorBase &, const double, const double, const double) = &OsiSolverInterface::addCol;
void    (OsiSolverInterface::*addCol_1)(const CoinPackedVectorBase &, const double , const double , const double , std::string ) = &OsiSolverInterface::addCol;

void    (OsiSolverInterface::*addRow_0)(const CoinPackedVectorBase &vec, const double rowlb, const double rowub) = &OsiSolverInterface::addRow;
void    (OsiSolverInterface::*addRow_1)(const CoinPackedVectorBase &vec, const double rowlb, const double rowub, std::string name) = &OsiSolverInterface::addRow;
void    (OsiSolverInterface::*addRow_2)(const CoinPackedVectorBase &vec, const char rowsen, const double rowrhs, const double rowrng) = &OsiSolverInterface::addRow;
void    (OsiSolverInterface::*addRow_3)(const CoinPackedVectorBase &vec, const char rowsen, const double rowrhs, const double rowrng, std::string name) = &OsiSolverInterface::addRow;

void    (OsiSolverInterface::*assignProblem_0)(CoinPackedMatrix *&matrix, double *&collb, double *&colub, double *&obj, double *&rowlb, double *&rowub) = &OsiSolverInterface::assignProblem;
void    (OsiSolverInterface::*assignProblem_1)(CoinPackedMatrix *&matrix, double *&collb, double *&colub, double *&obj, char *&rowsen, double *&rowrhs, double *&rowrng) = &OsiSolverInterface::assignProblem;

int     readMps_0(OsiSolverInterface* self, const char * name) { return self->readMps(name); }
int     (OsiSolverInterface::*readMps_1)(const char *, const char *) = &OsiSolverInterface::readMps;
int     (OsiSolverInterface::*readMps_2)(const char *, const char *, int &, CoinSet **&) = &OsiSolverInterface::readMps;

int     readLp_0(OsiSolverInterface* self, const char * name) { return self->readLp(name); }

bool    (OsiSolverInterface::*getHintParam_0)(OsiHintParam key, bool &yesNo, OsiHintStrength &strength, void *&otherInformation) const = &OsiSolverInterface::getHintParam;
bool    (OsiSolverInterface::*getHintParam_1)(OsiHintParam key, bool &yesNo, OsiHintStrength &strength) const = &OsiSolverInterface::getHintParam;
bool    (OsiSolverInterface::*getHintParam_2)(OsiHintParam key, bool &yesNo)  const = &OsiSolverInterface::getHintParam;

cptr_double OsiSolverInterface_getColSolution(OsiSolverInterface * self) { return cptr_double(self->getColSolution(), self->getNumCols() ); }
cptr_double OsiSolverInterface_getColLower(OsiSolverInterface * self) { return cptr_double(self->getColLower(), self->getNumCols() ); }
cptr_double OsiSolverInterface_getColUpper(OsiSolverInterface * self) { return cptr_double(self->getColUpper(), self->getNumCols() ); }
cptr_char   OsiSolverInterface_getRowSense(OsiSolverInterface * self) { return cptr_char(self->getRowSense(), self->getNumRows() ); }
cptr_double OsiSolverInterface_getRightHandSide(OsiSolverInterface * self) { return cptr_double(self->getRightHandSide(), self->getNumRows() ); }
cptr_double OsiSolverInterface_getRowRange(OsiSolverInterface * self) { return cptr_double(self->getRowRange(), self->getNumRows() ); }
cptr_double OsiSolverInterface_getRowLower(OsiSolverInterface * self) { return cptr_double(self->getRowLower(), self->getNumRows() ); }
cptr_double OsiSolverInterface_getRowUpper(OsiSolverInterface * self) { return cptr_double(self->getRowUpper(), self->getNumRows() ); }
cptr_double OsiSolverInterface_getObjCoefficients(OsiSolverInterface * self) { return cptr_double(self->getObjCoefficients(), self->getNumCols() ); }
cptr_double OsiSolverInterface_getRowPrice(OsiSolverInterface * self) { return cptr_double(self->getRowPrice(), self->getNumRows() ); }
cptr_double OsiSolverInterface_getReducedCost(OsiSolverInterface * self) { return cptr_double(self->getReducedCost(), self->getNumCols() ); }
cptr_double OsiSolverInterface_getRowActivity(OsiSolverInterface * self) { return cptr_double(self->getRowActivity(), self->getNumRows() ); }

// methods to load a problem
void (OsiSolverInterface::*loadProblem_0)(const CoinPackedMatrix &matrix, const double *collb, const double *colub, const double *obj, const double *rowlb, const double *rowub) = &OsiSolverInterface::loadProblem;
void (OsiSolverInterface::*loadProblem_1)(const CoinPackedMatrix &matrix, const double *collb, const double *colub, const double *obj, const char *rowsen, const double *rowrhs, const double *rowrng) = &OsiSolverInterface::loadProblem;
void OsiSolverInterface_loadProblem_2(OsiSolverInterface * self,
                    const int numcols, const int numrows,
                    const ptr_int & start, const ptr_int & index, const ptr_double & value,
                    const ptr_double & collb, const ptr_double & colub, const ptr_double & obj,
                    const ptr_double & rowlb, const ptr_double & rowub) {                       
    self->loadProblem(numcols,
                      numrows,
                      start.ptr(),
                      index.ptr(),
                      value.ptr(),
                      collb.ptr(),
                      colub.ptr(),
                      obj.ptr(),
                      rowlb.ptr(),
                      rowub.ptr());
}
void OsiSolverInterface_loadProblem_3(OsiSolverInterface * self,
                    const int numcols, const int numrows,
                    const ptr_int & start, const ptr_int & index, const ptr_double & value,
                    const ptr_double & collb, const ptr_double & colub, const ptr_double & obj,
                    const ptr_char & rowsen, const ptr_double & rowrhs, const ptr_double & rowrng) {
    self->loadProblem(numcols,
                      numrows,
                      start.ptr(),
                      index.ptr(),
                      value.ptr(),
                      collb.ptr(),
                      colub.ptr(),
                      obj.ptr(),
                      rowsen.ptr(),
                      rowrhs.ptr(),
                      rowrng.ptr());                    
}

// methods to query the constraint matrix
const_ptr_Wrap<CoinPackedMatrix> OsiSolverInterface_getMatrixByRow (OsiSolverInterface * self) { return const_ptr_Wrap<CoinPackedMatrix>(self->getMatrixByRow()); }    
const_ptr_Wrap<CoinPackedMatrix> OsiSolverInterface_getMatrixByCol (OsiSolverInterface * self) { return const_ptr_Wrap<CoinPackedMatrix>(self->getMatrixByCol()); }    
    

// methods to modify a problem
void OsiSolverInterface_addCol_2(OsiSolverInterface * self,
                int nelem, const ptr_int & rows, const ptr_double & coeff,
                const double collb, const double colub, const double obj) {
    self->addCol( nelem, rows.ptr() , coeff.ptr(), collb, colub, obj );
}
void OsiSolverInterface_addCol_3(OsiSolverInterface * self,
                int nelem, const ptr_int & rows, const ptr_double & coeff,
                const double collb, const double colub, const double obj, const boost::python::str & name) {
    self->addCol( nelem, rows.ptr() , coeff.ptr(), collb, colub, obj, std::string(boost::python::extract<char const*>(name)) );
}
void OsiSolverInterface_deleteCols(OsiSolverInterface * self, int ncols, const ptr_int & index) { 
    self->deleteCols(ncols, index.ptr());
}  

void OsiSolverInterface_addRow_4 (OsiSolverInterface * self,
                int numberElements, const ptr_int & columns, const ptr_double & elements,
                const double rowlb, const double rowub) {
    self->addRow( numberElements,
                  columns.ptr(),
                  elements.ptr(),
                  rowlb, rowub);
}
void OsiSolverInterface_deleteRows(OsiSolverInterface * self, int nind, const ptr_int & indices) { 
    self->deleteRows( nind , indices.ptr());
}

void OsiSolverInterface_writeMps(const OsiSolverInterface * self, const boost::python::str & name) { 
    self->writeMps(boost::python::extract<char const*>(name));
}   
    
using namespace boost::python;
   
// Binding
BOOST_PYTHON_MODULE(pyOsiCommon)
{
    enum_<OsiIntParam>("OsiIntParam")
        .value("OsiMaxNumIteration", OsiMaxNumIteration)
        .value("OsiMaxNumIterationHotStart", OsiMaxNumIterationHotStart)
        .value("OsiNameDiscipline", OsiNameDiscipline)
        .value("OsiLastIntParam", OsiLastIntParam)
    ;

    enum_<OsiDblParam>("OsiDblParam")
        .value("OsiDualObjectiveLimit", OsiDualObjectiveLimit)
        .value("OsiPrimalObjectiveLimit", OsiPrimalObjectiveLimit)
        .value("OsiDualTolerance", OsiDualTolerance)
        .value("OsiPrimalTolerance", OsiPrimalTolerance)
        .value("OsiObjOffset", OsiObjOffset)
        .value("OsiLastDblParam", OsiLastDblParam)
    ;
     
    enum_<OsiStrParam>("OsiStrParam")
        .value("OsiProbName", OsiProbName)
        .value("OsiSolverName", OsiSolverName)
        .value("OsiLastStrParam", OsiLastStrParam)
    ;
     
    enum_<OsiHintParam>("OsiHintParam")
        .value("OsiDoPresolveInInitial", OsiDoPresolveInInitial)
        .value("OsiDoDualInInitial", OsiDoDualInInitial)
        .value("OsiDoPresolveInResolve", OsiDoPresolveInResolve)
        .value("OsiDoDualInResolve", OsiDoDualInResolve)
        .value("OsiDoScale", OsiDoScale)
        .value("OsiDoCrash", OsiDoCrash)
        .value("OsiDoReducePrint", OsiDoReducePrint)
        .value("OsiDoInBranchAndCut", OsiDoInBranchAndCut)
        .value("OsiLastHintParam", OsiLastHintParam)
    ;
     
    enum_<OsiHintStrength>("OsiHintStrength")
        .value("OsiHintIgnore", OsiHintIgnore)
        .value("OsiHintTry", OsiHintTry)
        .value("OsiHintDo", OsiHintDo)
        .value("OsiForceDo", OsiForceDo)
    ;
    
    class_< cptr_double >("Const_double_array")
        .def("__len__", &cptr_double::length )
        .def("__getitem__", &cptr_double::getItem , return_value_policy<copy_const_reference>() )
        .def("__repr__", &cptr_double::repr)
        .def("__iter__", &cptr_double::iter, return_value_policy<copy_const_reference>() )
        .def("next",&cptr_double::next, return_value_policy<copy_const_reference>() )
    ; 

    class_< cptr_char >("Const_char_array")
        .def("__len__", &cptr_char::length )
        .def("__getitem__", &cptr_char::getItem , return_value_policy<copy_const_reference>() )
        .def("__repr__", &cptr_char::repr)
        .def("__iter__", &cptr_char::iter, return_value_policy<copy_const_reference>() )
        .def("next",&cptr_char::next, return_value_policy<copy_const_reference>() )
    ;
 
    class_< cptr_int >("Const_int_array")
        .def("__len__", &cptr_int::length )
        .def("__getitem__", &cptr_int::getItem , return_value_policy<copy_const_reference>() )
        .def("__repr__", &cptr_int::repr)
        .def("__iter__", &cptr_int::iter, return_value_policy<copy_const_reference>() )
        .def("next",&cptr_int::next, return_value_policy<copy_const_reference>() )
    ;
 
    class_< ptr_double, boost::noncopyable >("Double_array")
        .def(init<arraySize>() )
        .def("__len__", &ptr_double::length )
        .def("__setitem__", &ptr_double::setItem)
        .def("__getitem__", &ptr_double::getItem , return_value_policy<copy_const_reference>() )
        .def("fill", &ptr_double::fill )
        .def("__repr__", &ptr_double::repr)
    ; 

    class_< ptr_char, boost::noncopyable >("Char_array")
        .def(init<arraySize>() )
        .def("__len__", &ptr_char::length )
        .def("__setitem__", &ptr_char::setItem)
        .def("__getitem__", &ptr_char::getItem , return_value_policy<copy_const_reference>() )
        .def("fill", &ptr_char::fill )
        .def("__repr__", &ptr_char::repr)
    ;
        
    class_< ptr_int, boost::noncopyable >("Int_array")
        .def(init<arraySize>() )
        .def("__len__", &ptr_int::length )
        .def("__setitem__", &ptr_int::setItem)
        .def("__getitem__", &ptr_int::getItem , return_value_policy<copy_const_reference>() )
        .def("fill", &ptr_int::fill )
        .def("__repr__", &ptr_int::repr)
    ;
    
    class_< WarmStartWrap, boost::noncopyable >("WarmStart")
    ;
    
    class_< const_ptr_Wrap<CoinPackedMatrix> >("ConstCoinPackedMatrix")
        .def("__len__", &const_ptr_Wrap<CoinPackedMatrix>::length )
        .def("__getitem__", &const_ptr_Wrap<CoinPackedMatrix>::getItem )
        .def("__repr__", &const_ptr_Wrap<CoinPackedMatrix>::repr)
    ;
    
    class_<OSIWrap, boost::noncopyable>("OsiSolverInterface")
        .def("initialSolve", pure_virtual(&OsiSolverInterface::initialSolve))
        .def("resolve", pure_virtual(&OsiSolverInterface::resolve))
        .def("branchAndBound", pure_virtual(&OsiSolverInterface::branchAndBound))
        .def("isAbandoned", pure_virtual(&OsiSolverInterface::isAbandoned))
        .def("isProvenOptimal", pure_virtual(&OsiSolverInterface::isProvenOptimal))
        .def("isProvenPrimalInfeasible", pure_virtual(&OsiSolverInterface::isProvenPrimalInfeasible))
        .def("isProvenDualInfeasible", pure_virtual(&OsiSolverInterface::isProvenDualInfeasible))
        .def("isPrimalObjectiveLimitReached", pure_virtual(&OsiSolverInterface::isPrimalObjectiveLimitReached))
        .def("isDualObjectiveLimitReached", pure_virtual(&OsiSolverInterface::isDualObjectiveLimitReached))
        .def("isIterationLimitReached", pure_virtual(&OsiSolverInterface::isIterationLimitReached))
        .def("getEmptyWarmStart", pure_virtual(&OsiSolverInterface::getEmptyWarmStart), return_value_policy<manage_new_object>())
        .def("getWarmStart", pure_virtual(&OsiSolverInterface::getWarmStart), return_value_policy<manage_new_object>())
        .def("setWarmStart", pure_virtual(&OsiSolverInterface::setWarmStart))
        .def("getNumCols", pure_virtual(&OsiSolverInterface::getNumCols))
        .def("getNumRows", pure_virtual(&OsiSolverInterface::getNumRows))
        .def("getNumElements", pure_virtual(&OsiSolverInterface::getNumElements))
        .def("getColLower", OsiSolverInterface_getColLower)
        .def("getColUpper", OsiSolverInterface_getColUpper)
        .def("getRowSense", OsiSolverInterface_getRowSense)
        .def("getRightHandSide", OsiSolverInterface_getRightHandSide)
        .def("getRowRange", OsiSolverInterface_getRowRange)
        .def("getRowLower", OsiSolverInterface_getRowLower)
        .def("getRowUpper", OsiSolverInterface_getRowUpper)
        .def("getObjCoefficients", OsiSolverInterface_getObjCoefficients)
        .def("getObjSense", pure_virtual(&OsiSolverInterface::getObjSense))
        .def("isContinuous", pure_virtual(&OsiSolverInterface::isContinuous))
        .def("getMatrixByRow", OsiSolverInterface_getMatrixByRow )
        .def("getMatrixByCol", OsiSolverInterface_getMatrixByCol )
        .def("getInfinity", pure_virtual(&OsiSolverInterface::getInfinity)) 
        .def("getColSolution", OsiSolverInterface_getColSolution )
        .def("getRowPrice", OsiSolverInterface_getRowPrice)
        .def("getReducedCost", OsiSolverInterface_getReducedCost)
        .def("getRowActivity", OsiSolverInterface_getRowActivity)
        .def("getObjValue", pure_virtual(&OsiSolverInterface::getObjValue))
        .def("getIterationCount", pure_virtual(&OsiSolverInterface::getIterationCount))
        .def("getDualRays", pure_virtual(&OsiSolverInterface::getDualRays))
        .def("getPrimalRays", pure_virtual(&OsiSolverInterface::getPrimalRays))
        .def("setObjCoeff", pure_virtual(&OsiSolverInterface::setObjCoeff))
        .def("setObjSense", pure_virtual(&OsiSolverInterface::setObjSense))
        .def("setColLower", pure_virtual(setColLower_0))
        .def("setColLower", setColLower_1)
        .def("setColUpper", pure_virtual(setColUpper_0))
        .def("setColUpper", setColUpper_1)
        .def("setRowLower", pure_virtual(&OsiSolverInterface::setRowLower))
        .def("setRowUpper", pure_virtual(&OsiSolverInterface::setRowUpper))
        .def("setRowType", pure_virtual(&OsiSolverInterface::setRowType))
        .def("setColSolution", pure_virtual(&OsiSolverInterface::setColSolution))
        .def("setRowPrice", pure_virtual(&OsiSolverInterface::setRowPrice))
        .def("setContinuous", pure_virtual(setContinuous_0))
        .def("setContinuous", setContinuous_1)
        .def("setInteger", pure_virtual(setInteger_0))
        .def("setInteger", setInteger_1)
        .def("addCol", pure_virtual(addCol_0))
        .def("addCol", addCol_1)
        .def("addCol", OsiSolverInterface_addCol_2)
        .def("addCol", OsiSolverInterface_addCol_3)
        .def("deleteCols", OsiSolverInterface_deleteCols)
        .def("addRow", pure_virtual(addRow_0))
        .def("addRow", addRow_1)
        .def("addRow", pure_virtual(addRow_2))
        .def("addRow", addRow_3)
        .def("addRow", OsiSolverInterface_addRow_4)
        .def("deleteRows", OsiSolverInterface_deleteRows)
        .def("loadProblem", pure_virtual(loadProblem_0))
        .def("loadProblem", pure_virtual(loadProblem_1))
        .def("loadProblem", OsiSolverInterface_loadProblem_2)
        .def("loadProblem", OsiSolverInterface_loadProblem_3)
        .def("assignProblem", pure_virtual(assignProblem_0))
        .def("assignProblem", pure_virtual(assignProblem_1))
        .def("writeMps", pure_virtual(&OsiSolverInterface::writeMps))
        .def("clone", pure_virtual(&OsiSolverInterface::clone), return_value_policy<manage_new_object>()) 
        .def("readMps", readMps_0)
        .def("readMps", readMps_1)
        .def("readMps", readMps_2)
        .def("writeMps", OsiSolverInterface_writeMps)
        .def("readLp", readLp_0)
        .def("setIntParam", &OsiSolverInterface::setIntParam)
        .def("setDblParam", &OsiSolverInterface::setDblParam)
        .def("setStrParam", &OsiSolverInterface::setStrParam)
        .def("setHintParam", &OsiSolverInterface::setHintParam)
        .def("getIntParam", &OsiSolverInterface::getIntParam)
        .def("getDblParam", &OsiSolverInterface::getDblParam)
        .def("getIntegerTolerance", &OsiSolverInterface::getIntegerTolerance)
        .def("getStrParam", &OsiSolverInterface::getStrParam)
        .def("getHintParam", getHintParam_0)
        .def("getHintParam", getHintParam_1)
        .def("getHintParam", getHintParam_2)
        .def("copyParameters", &OsiSolverInterface::copyParameters)
        .def("markHotStart", &OsiSolverInterface::markHotStart)
        .def("solveFromHotStart", &OsiSolverInterface::solveFromHotStart)
        .def("unmarkHotStart",  &OsiSolverInterface::unmarkHotStart)    
    ;
}
